package com.LensBlaster;

import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.CursorIndexOutOfBoundsException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;

/**
 * A grid that displays a set of framed photos. Tied to 
 * LensBlasterDB class for information retrieval. To display
 * an album, the receiving bundle must contain an album ID
 * referring to a valid row in the albums table.
 * 
 * Users in this class may select a photo to view it, in 
 * which case they will be conveyed to the PhotoView. Users 
 * also have the option here to rename the album and delete
 * the album. 
 * 
 * This class duplicates a significant portion of code in the 
 * ImageAdapter member class with PhotoView, to be refactored 
 * for 2.0.
 * 
 * @author Jake
 */
public class AlbumView extends Activity {
	private static final int ACTIVITY_PHOTOVIEW=0;
	
	private static final int ALBUM_DELETE_ID = Menu.FIRST;
	private static final int ALBUM_RENAME_ID = Menu.FIRST+1;

	private LensBlasterDB mAlbumDB;
	private long mAlbumID;

	/**
	 * Called when the class is first created.
	 * 
	 * The bundle passed must contain the following:
	 * <ul>
	 * <li> Album ID (String) registered in the Albums table of
	 * of LensBlasterDB, and passed in as an extra, retrieved
	 * with key LensBlasterDB.ALBUM_KEY_ROWID.</li>
	 * 
	 * <li> Album String (String) also passed in as an extra, 
	 * retrieved with key "title". </li>

	 * @param savedInstanceState See above.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Bundle extras = getIntent().getExtras();

		mAlbumDB = new LensBlasterDB(this);
		mAlbumDB.open();

		mAlbumID = extras.getLong(LensBlasterDB.ALBUM_KEY_ROWID);
		
		android.util.Log.d("lens","opening album view with ALBUMID = " + mAlbumID);

		if (extras != null)
			setTitle(extras.getString(LensBlasterDB.ALBUM_KEY_TITLE));
		else
			setTitle("Album");
		
		fillData();
	}
	
	/**
	 * Refreshes the Album view
	 */
	public void fillData(){
		android.util.Log.d("lens","Filling data in AlbumView");
		
		setContentView(R.layout.album_thumbnail_grid);

		GridView g = (GridView) findViewById(R.id.myGrid);
		g.setAdapter(new ImageAdapter(this));
	}
	
	/**
	 * We construct the menu options here.
	 * @param menu The menu to which we add menu items.
	 * @return True to display the menu; false to keep it hidden.
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		
		if (this.mAlbumID != LensBlasterDB.ALL_PHOTOS_ALBUM_ID) { //check if all photos because...
			menu.add(0, ALBUM_RENAME_ID, 0, R.string.menu_album_rename); //can't rename the all photos album
			menu.add(0, ALBUM_DELETE_ID, 0, R.string.menu_album_delete); //same for delete
		}
		
		return true;
	}
	
	/**
	 * Handles a menu selection event
	 * @param featureId The panel that the menu is in.
	 * @param item The menu item that was selected.
	 * @return boolean Return true to finish processing of selection, or false to perform the normal menu handling (calling its Runnable or sending a Message to its target Handler).
	 */
	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch(item.getItemId()) {
		case ALBUM_RENAME_ID:
			renameAlbum();
			return true;
		case ALBUM_DELETE_ID:
			deleteAlbum();
			return true;
		}
		
		return super.onMenuItemSelected(featureId, item);
	}
	
	/**
	 * Private helper function to rename album. <br>
	 * Preconditions:
	 * <ul>
	 * <li>mAlbumDB is open</li>
	 * <li>mAlbumID is a valid ID on the Albums table, and not equal to LensBlasterDB.ALL_PHOTOS_ALBUM_ID</li>
	 * </ul>
	 * 
	 * Postcondition:
	 * <ul>
	 * <li>The title corresponding to mAlbumID on the Albums table is updated.</li>
	 * </ul>
	 */
	private void renameAlbum() {
		//TODO: formatting stuff, need to shove this to XML
		final FrameLayout fl = new FrameLayout(this); 
		final EditText input = new EditText(this);
		input.setLines(1);
		input.setGravity(Gravity.CENTER); 

		fl.addView(input, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT));
		
		input.setText(this.getTitle());
		
		new AlertDialog.Builder(this)
		.setMessage("Rename Album")
		.setView(fl)
		.setPositiveButton("Rename", 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					dialog.dismiss();
					boolean result = mAlbumDB.updateAlbum(mAlbumID, input.getText().toString());
					if (result)
						setTitle(input.getText().toString());
					
					Bundle bundle = new Bundle();

			        Intent mIntent = new Intent();
			        mIntent.putExtras(bundle);
			        setResult(RESULT_OK, mIntent);
				}
			})
		.setCancelable(true)
		.setNegativeButton("Cancel", 
			new DialogInterface.OnClickListener() { 
				public void onClick(DialogInterface dialog, int which) { 
					dialog.dismiss(); 
				}
			})
        .create()
		.show();
	}
	
	/**
	 * Private helper function to delete album. <br>
	 * Preconditions:
	 * <ul>
	 * <li>mAlbumDB is open</li>
	 * <li>mAlbumID is a valid ID on the Albums table, and not equal to LensBlasterDB.ALL_PHOTOS_ALBUM_ID</li>
	 * </ul>
	 * 
	 * Postconditions:
	 * <ul>
	 * <li>mAlbumID no longer exists on the Albums table</li>
	 * </ul>
	 */
	private void deleteAlbum() {
		new AlertDialog.Builder(this)
		.setMessage("Delete this album?")
		.setPositiveButton("Delete", 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int whichButton) {
					dialog.dismiss();
					
					Bundle bundle = new Bundle();
			           
			        Intent mIntent = new Intent();
			        mIntent.putExtras(bundle);
			        setResult(RESULT_OK, mIntent);
					
					mAlbumDB.deleteAlbum(mAlbumID);
					finish();
				}
			})
		.setCancelable(true)
		.setNegativeButton("Cancel",  
			new DialogInterface.OnClickListener() { 
				public void onClick(DialogInterface dialog, int which) { 
					dialog.dismiss(); 
				}
			})
        .create()
		.show();
	}
	
	/**
	 * Handles a return to this activity from the activity we called.
	 * @param requestCode The code of the request we packaged into the Intent that opened the Activity we called.
	 * @param resultCode The code of the result (i.e., OK). We ignore this.
	 * @param intent The initial intent we passed into the activity we called. We ignore this, too.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
		if (intent!=null) {
			super.onActivityResult(requestCode, resultCode, intent);
				
			switch(requestCode) {
			case ACTIVITY_PHOTOVIEW:
				fillData();
				break;
			}
		}
	}
	
	/**
	 * Called when destroying this activity.
	 * Postcondition:
	 * <ul>
	 * <li>mDbHelper is closed</li>
	 * <ul>
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();
		mAlbumDB.close();
	}

	/**
	 * Inner class that prepares photo thumbnails for the GridView.
	 * @author Jake
	 */
	public class ImageAdapter extends BaseAdapter {
		private final Context mContext;
		
		public ImageAdapter(Context c) {
			mContext = c;
		}

		/**
		 * How many items are in the data set represented by this ImageAdapter.
		 * @return Count of items.
		 */
		public int getCount() {
			Cursor c = mAlbumDB.fetchPhotosByAlbum(mAlbumID);
			int count = c.getCount();
			c.close();
			return count;
		}

		/**
		 * Get the position associated with the specified position in the album.
		 * Never used.
		 * @param The position associated with the specified position in the album.
		 * @return The position passed in.
		 */
		public Object getItem(int position) {
			return position;
		}

		/**
		 * Retrieves the ID of the photo of the thumbnail we wish to display.
		 * @param position the position of the thumbnail we wish to display.
		 * @return the ID of the photo of the thumbnail we wish to display.
		 */
		public long getItemId(int position) {
			Cursor c = mAlbumDB.fetchPhotosByAlbum(mAlbumID);
			c.moveToPosition(position);
			Long photoID = c.getLong(c.getColumnIndex(LensBlasterDB.PA_KEY_PHOTOID));
			c.close();

			return (photoID);
		}

		/**
		 * Get a View that displays the photo thumbnail at the specified position in the data set. 
		 * @param position The position of the photo within the adapter's data set whose thumbnail 
		 * we want.
		 * @param convertView The old view to reuse, if possible. Note: You should check that this 
		 * view is non-null and of an appropriate type before using. If it is not possible to 
		 * convert this view to display the correct data, this method can create a new view.
		 * @return view A View with the thumbnail we requested.
		 */
		public View getView(final int position, View convertView, ViewGroup parent) {
			if (convertView!=null) { //if it ain't null, we can just display the cached view
				//but we need to account for a weird bug in the GridView class where 
				//convertView may be the first image in the grid, regardless of position
				if (convertView.getId()==position)
					return (ImageView) convertView;
			}
			
			final long photoID = getItemId(position);
			android.util.Log.d("lens","photoID="+photoID+" position="+position);
			Cursor photo = managedQuery(
					MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null,
					MediaStore.Images.ImageColumns._ID + "=" + "'" + photoID + "'", null, null);
			startManagingCursor(photo);
			photo.moveToFirst();
			
			Cursor thumbnail = managedQuery(
					MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null,
					MediaStore.Images.Thumbnails.IMAGE_ID + "=" + "'" + photoID + "'", null, null);
			startManagingCursor(thumbnail);
			thumbnail.moveToFirst();

			int dataColIdx;			
			String imageData;
			
			try { 
				//trying to fetch the photo's associated thumbnail Uri
				dataColIdx = thumbnail.getColumnIndex(android.provider.MediaStore.Images.Thumbnails.DATA);
				imageData = thumbnail.getString(dataColIdx); //Throws CursorIndexOutOfBoundsExceptions
				android.util.Log.d("lens","photoID="+photoID+" imageData="+imageData);
			} catch (CursorIndexOutOfBoundsException e) {
				try { 
					//when that fails, manually generate the thumbnail, and try again
					MediaStore.Images.Media.insertImage(
							mContext.getContentResolver(), 
							photo.getColumnName(photo.getColumnIndex(MediaStore.Images.Media.DATA)), 
							"", "");
					thumbnail.requery();
					thumbnail.moveToFirst();
					
					imageData = thumbnail.getString(thumbnail.getColumnIndex(MediaStore.Images.Media.DATA));
				} catch (FileNotFoundException f) { 
					//at the very least, just fetch the actual photo
					//this is bad because it's processor- and memory-intensive, but
					//chances of getting this far are rare
					//TODO: turn this into a proxy process, and generate the images in the background
					dataColIdx = photo.getColumnIndex(android.provider.MediaStore.Images.Media.DATA);
					imageData = photo.getString(dataColIdx);
				}
			}
			
			final Uri dataURI = Uri.parse(imageData);
			
			ImageView imageView = new ImageView(mContext);
			//TODO: formatting stuff, need to shove this to XML
			imageView.setLayoutParams(new GridView.LayoutParams(90, 90));
			imageView.setAdjustViewBounds(false);
			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
			imageView.setId(position);
			imageView.setOnClickListener(new View.OnClickListener() {
				private Uri imageURI = dataURI;

				public void onClick(View view) {
					Intent mIntent = new Intent(mContext, PhotoView.class);
					
					// need to pass in position of the photo, as well as point to it
					mIntent.setData(imageURI);
					mIntent.putExtra("position", position);
					mIntent.putExtra(LensBlasterDB.PA_KEY_PHOTOID, String.valueOf(photoID));
					mIntent.putExtra(LensBlasterDB.ALBUM_KEY_ROWID, mAlbumID);

					startActivityForResult(mIntent, ACTIVITY_PHOTOVIEW);
				}
			});
			
			Bitmap bm = BitmapFactory.decodeFile(dataURI.getPath());
			imageView.setImageBitmap(Bitmap.createScaledBitmap(bm, bm.getWidth()/4, bm.getHeight()/4, false));

			return imageView;
		}
	}
}
